/* 
  Copyright (c) SilverLining 2015
  Date:    2016-1-7
  File:    error.cpp  
  Description: 

*/

#include "stdafx.h"
#include "m_provider.h"

namespace m
{
	namespace error
	{
		debug_provider dbg;
		__declspec(thread) result LastHr = 0;

		debug_provider::debug_provider()
		{
			EventRegisterSL_M_TraceProvider();
			OutputDebugString(L"This process provides ETW logging events.\n");
			//ProviderGuid
			// {043AA552-CEDD-4573-9DD0-D6CFC1115BC4}
			WCHAR GuidString[60] = { 0 };
			swprintf_s(GuidString, L"  ProviderGuid: {%8x-%4x-%4x-%8x%8x}\n", ProviderGuid.Data1, ProviderGuid.Data2, ProviderGuid.Data3, *((unsigned int*)&ProviderGuid.Data4[0]), *((unsigned int*)&ProviderGuid.Data4[5]));
			OutputDebugString(GuidString);
		}

		debug_provider::~debug_provider()
		{
			EventUnregisterSL_M_TraceProvider();
		}

		void debug_provider::log(result hr, const wchar_t* Fmt, ...)
		{
			FILETIME time = SysTime();
			DWORD tid = ThreadId();
			va_list args;
			va_start(args, Fmt);
			wchar_t* msg = FormatV(Fmt, args);
			EventWriteDebug(hr, &time, msg, tid);
			delete[] msg;
			va_end(args);
		}

		void debug_provider::alloc(void* ptr, size_t sz)
		{
			FILETIME time = SysTime();
			DWORD tid = ThreadId();
			EventWriteMemory(ptr, sz, 0, tid, &time);
		}

		void debug_provider::_free(void* ptr)
		{
			FILETIME time = SysTime();
			DWORD tid = ThreadId();
			EventWriteMemory(ptr, 0, 1, tid, &time);
		}

		void debug_provider::reference(void* ptr, const size_t& refCount)
		{
			FILETIME time = SysTime();
			DWORD tid = ThreadId();
			EventWriteReference(ptr, 0, refCount, tid, &time);
		}

		void debug_provider::referenceweak(void* ptr)
		{
			FILETIME time = SysTime();
			DWORD tid = ThreadId();
			EventWriteReference(ptr, 1, 1, tid, &time);
		}

		void debug_provider::release(void* ptr, const size_t& refCount)
		{
			FILETIME time = SysTime();
			DWORD tid = ThreadId();
			EventWriteReference(ptr, 2, refCount, tid, &time);
		}

		void debug_provider::message(const wchar_t* messageType, void * sender, void * data)
		{
			FILETIME time = SysTime();
			EventWriteMessage(messageType, sender, data, &time);
		}
			
		DWORD debug_provider::ThreadId()
		{
			return GetThreadId(GetCurrentThread());
		}

		FILETIME debug_provider::SysTime()
		{
			FILETIME ret;
			*((ULONGLONG*)&ret) = GetTickCount64();
			return ret;
		}

		wchar_t* debug_provider::FormatV(const wchar_t* Fmt, va_list args)
		{
			size_t len = _vscwprintf(Fmt, args);
			++len;
			wchar_t* Buf = new WCHAR[len];
			len = vswprintf_s(Buf, len, Fmt, args);
			return Buf;
		}
	} // error
} // m